package com.insight.controller;

import com.insight.common.enums.CollectionType;
import com.insight.common.enums.TaskStatus;
import com.insight.common.exception.ResourceNotFoundException;
import com.insight.dto.collection.CollectionTaskCreateRequest;
import com.insight.dto.collection.CollectionTaskResponse;
import com.insight.dto.collection.TaskHealthResponse;
import com.insight.entity.CollectionTask;
import com.insight.entity.DataSource;
import com.insight.mapper.CollectionTaskMapper;
import com.insight.service.CollectionTaskService;
import com.insight.service.DataSourceService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
import com.insight.datasource.adapter.MetadataExtractor;
import com.insight.datasource.adapter.MetadataExtractorFactory;
import com.insight.service.MetadataCollectionService;
import java.util.concurrent.CompletableFuture;

/**
 * 采集任务管理REST API控制器
 * 实现采集任务CRUD操作和任务管理的RESTful接口
 *
 * @author Insight Team
 */
@Slf4j
@RestController
@RequestMapping("/api/v1/collection-tasks")
@RequiredArgsConstructor
@Tag(name = "Collection Task Management", description = "元数据采集任务管理API")
public class CollectionTaskController {

    private final CollectionTaskService collectionTaskService;
    private final DataSourceService dataSourceService;
    private final CollectionTaskMapper collectionTaskMapper;
    private final MetadataCollectionService metadataCollectionService;
    private final MetadataExtractorFactory extractorFactory;


    /**
     * 查询采集任务列表
     *
     * @param pageable 分页参数
     * @param datasourceId 数据源ID（可选）
     * @param status 任务状态（可选）
     * @param type 采集类型（可选）
     * @return 采集任务分页列表
     */
    @GetMapping
    @Operation(summary = "查询采集任务列表", description = "分页查询采集任务，支持按数据源、状态、类型过滤")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "查询成功")
    })
    public ResponseEntity<com.insight.common.response.ApiResponse<Page<CollectionTaskResponse>>> listCollectionTasks(
            @PageableDefault(size = 20, sort = "createdAt") Pageable pageable,
            @Parameter(description = "数据源ID") @RequestParam(required = false) Long datasourceId,
            @Parameter(description = "任务状态") @RequestParam(required = false) TaskStatus status,
            @Parameter(description = "采集类型") @RequestParam(required = false) CollectionType type) {

        log.debug("API: 查询采集任务列表 - page={}, size={}, datasourceId={}, status={}, type={}",
                pageable.getPageNumber(), pageable.getPageSize(), datasourceId, status, type);

        Page<CollectionTask> page;

        // 根据不同条件查询
        if (datasourceId != null) {
            page = collectionTaskService.findByDataSource(datasourceId, pageable);
        } else if (status != null) {
            page = collectionTaskService.findByStatus(status, pageable);
        } else if (type != null) {
            page = collectionTaskService.findByType(type, pageable);
        } else {
            page = collectionTaskService.findAll(pageable);
        }

        // 转换为响应对象
        Page<CollectionTaskResponse> responsePage = page.map(collectionTaskMapper::toResponse);

        return ResponseEntity.ok(com.insight.common.response.ApiResponse.success(responsePage));
    }



    /**
     * 创建采集任务
     *
     * @param request 创建请求
     * @return 创建的采集任务响应
     */
    @PostMapping
    @Operation(summary = "创建采集任务", description = "创建元数据采集任务,支持全量和增量采集")
    @ApiResponses({
            @ApiResponse(responseCode = "201", description = "创建成功",
                    content = @Content(schema = @Schema(implementation = CollectionTaskResponse.class))),
            @ApiResponse(responseCode = "400", description = "请求参数验证失败"),
            @ApiResponse(responseCode = "404", description = "数据源不存在")
    })
    public ResponseEntity<com.insight.common.response.ApiResponse<CollectionTaskResponse>> createCollectionTask(
            @Valid @RequestBody CollectionTaskCreateRequest request) {

        log.info("API: 创建采集任务 - datasourceId={}, type={}", request.getDatasourceId(), request.getType());

        // 查找数据源
        DataSource dataSource = dataSourceService.findById(request.getDatasourceId())
                .orElseThrow(() -> new ResourceNotFoundException("数据源不存在: id=" + request.getDatasourceId()));

        // 创建任务
        CollectionTask task = collectionTaskService.createTask(dataSource, request.getType());

        // 转换为响应DTO
        CollectionTaskResponse response = collectionTaskMapper.toResponse(task);

        URI location = URI.create(String.format("/api/v1/collection-tasks/%d", response.getId()));
        return ResponseEntity.created(location)
                .body(com.insight.common.response.ApiResponse.success(response));
    }

    /**
     * 根据ID获取采集任务
     *
     * @param id 任务ID
     * @return 任务响应
     */
    @GetMapping("/{id}")
    @Operation(summary = "获取任务详情", description = "查询采集任务详细信息和进度")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "查询成功",
                    content = @Content(schema = @Schema(implementation = CollectionTaskResponse.class))),
            @ApiResponse(responseCode = "404", description = "任务不存在")
    })
    public ResponseEntity<com.insight.common.response.ApiResponse<CollectionTaskResponse>> getCollectionTask(
            @Parameter(description = "任务ID") @PathVariable Long id) {

        log.debug("API: 查询采集任务 - id={}", id);

        CollectionTask task = collectionTaskService.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("采集任务不存在: id=" + id));

        CollectionTaskResponse response = collectionTaskMapper.toResponse(task);
        return ResponseEntity.ok(com.insight.common.response.ApiResponse.success(response));
    }

    /**
     * 启动采集任务
     *
     * @param id 任务ID
     * @return 任务响应
     */
    @PostMapping("/{id}/start")
    @Operation(summary = "启动采集任务", description = "启动PENDING状态的采集任务,开始执行元数据采集")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "启动成功"),
            @ApiResponse(responseCode = "404", description = "任务不存在"),
            @ApiResponse(responseCode = "409", description = "任务状态不允许启动")
    })
    public ResponseEntity<com.insight.common.response.ApiResponse<CollectionTaskResponse>> startCollectionTask(
            @Parameter(description = "任务ID") @PathVariable Long id) {

        log.info("API: 启动采集任务 - id={}", id);

        try {
            // 1. 查找任务
            CollectionTask task = collectionTaskService.findById(id)
                    .orElseThrow(() -> new ResourceNotFoundException("任务不存在: id=" + id));
            
            // 2. 查找数据源
            DataSource dataSource = dataSourceService.findById(task.getDataSource().getId())
                    .orElseThrow(() -> new ResourceNotFoundException("数据源不存在"));
            
            // 3. 创建对应的MetadataExtractor
            MetadataExtractor extractor = extractorFactory.createExtractor(dataSource.getDbType());
            
            // 4. 异步执行采集任务(带超时机制) - 使用已创建的任务ID
            CompletableFuture.runAsync(() -> {
                try {
                    log.info("开始异步执行采集任务: taskId={}, datasource={}", id, dataSource.getName());
                    // 使用新的方法签名,传入已存在的任务ID
                    metadataCollectionService.collectFullMetadata(id, dataSource, extractor);
                    log.info("采集任务完成: taskId={}", id);
                } catch (Exception e) {
                    log.error("采集任务执行失败: taskId={}, error={}", id, e.getMessage(), e);
                    try {
                        collectionTaskService.failTask(id, e.getMessage());
                    } catch (Exception ex) {
                        log.error("更新任务失败状态时出错: taskId={}", id, ex);
                    }
                }
            })
            .orTimeout(60, java.util.concurrent.TimeUnit.MINUTES)  // 60分钟超时
            .exceptionally(ex -> {
                if (ex instanceof java.util.concurrent.TimeoutException) {
                    log.error("采集任务超时: taskId={}", id);
                    try {
                        collectionTaskService.failTask(id, "任务执行超时(60分钟)");
                    } catch (Exception failEx) {
                        log.error("更新任务超时状态失败: taskId={}", id, failEx);
                    }
                }
                return null;
            });
            
            // 5. 立即返回任务信息（任务在异步线程中已启动）
            // 注意: collectFullMetadata内部已调用startTask,无需重复调用
            task = collectionTaskService.findById(id)
                    .orElseThrow(() -> new ResourceNotFoundException("任务不存在: id=" + id));
            CollectionTaskResponse response = collectionTaskMapper.toResponse(task);
            return ResponseEntity.ok(com.insight.common.response.ApiResponse.success(response));
            
        } catch (IllegalArgumentException e) {
            throw new ResourceNotFoundException(e.getMessage());
        } catch (IllegalStateException e) {
            return ResponseEntity.status(HttpStatus.CONFLICT)
                    .body(com.insight.common.response.ApiResponse.error("任务状态不允许启动: " + e.getMessage()));
        }
    }


    /**
     * 取消采集任务
     *
     * @param id 任务ID
     * @return 任务响应
     */
    @PostMapping("/{id}/cancel")
    @Operation(summary = "取消采集任务", description = "取消PENDING或RUNNING状态的采集任务")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "取消成功"),
            @ApiResponse(responseCode = "404", description = "任务不存在"),
            @ApiResponse(responseCode = "409", description = "任务状态不允许取消")
    })
    public ResponseEntity<com.insight.common.response.ApiResponse<CollectionTaskResponse>> cancelCollectionTask(
            @Parameter(description = "任务ID") @PathVariable Long id) {

        log.info("API: 取消采集任务 - id={}", id);

        try {
            CollectionTask task = collectionTaskService.cancelTask(id);
            CollectionTaskResponse response = collectionTaskMapper.toResponse(task);
            return ResponseEntity.ok(com.insight.common.response.ApiResponse.success(response));
        } catch (IllegalStateException e) {
            return ResponseEntity.status(HttpStatus.CONFLICT)
                    .body(com.insight.common.response.ApiResponse.error("任务状态不允许取消: " + e.getMessage()));
        }
    }

    /**
     * 检查任务健康状态
     *
     * @param id 任务ID
     * @return 健康检查响应
     */
    @GetMapping("/{id}/health")
    @Operation(summary = "任务健康检查", description = "检查RUNNING状态任务是否健康，识别卡住的任务")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "检查成功"),
            @ApiResponse(responseCode = "404", description = "任务不存在")
    })
    public ResponseEntity<com.insight.common.response.ApiResponse<TaskHealthResponse>> checkTaskHealth(
            @Parameter(description = "任务ID") @PathVariable Long id) {

        log.debug("API: 检查任务健康状态 - id={}", id);

        CollectionTask task = collectionTaskService.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("任务不存在: id=" + id));

        TaskHealthResponse healthResponse = collectionTaskService.checkTaskHealth(task);
        return ResponseEntity.ok(com.insight.common.response.ApiResponse.success(healthResponse));
    }

    /**
     * 全局异常处理
     */
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<com.insight.common.response.ApiResponse<Void>> handleResourceNotFound(
            ResourceNotFoundException ex) {

        log.warn("资源不存在: {}", ex.getMessage());

        return ResponseEntity.status(HttpStatus.NOT_FOUND)
                .body(com.insight.common.response.ApiResponse.error(ex.getMessage()));
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<com.insight.common.response.ApiResponse<Void>> handleIllegalArgument(
            IllegalArgumentException ex) {

        log.warn("参数验证失败: {}", ex.getMessage());

        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(com.insight.common.response.ApiResponse.error("参数验证失败: " + ex.getMessage()));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<com.insight.common.response.ApiResponse<Void>> handleGenericException(Exception ex) {
        log.error("未预期的异常", ex);

        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(com.insight.common.response.ApiResponse.error("Internal server error: " + ex.getMessage()));
    }
}
